home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / ded / ded.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-10-31  |  37.0 KB  |  1,612 lines

  1. #ifndef lint
  2. static char RCSid[] = "$Header: ded.c,v 1.9 84/04/25 04:05:32 lepreau Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Directory editor.
  7.  *    ded <options> [dir] [files]
  8.  *
  9.  * Stuart Cracraft, SRI, Sept 1980
  10.  * Jay Lepreau, Univ of Utah, 1981, 82, 83, 84
  11.  *
  12.  *     The following may be defined as quoted strings to override
  13.  *     the defaults.  Only the last need be a full pathname.
  14.  * DEDNAME      ded's own name.
  15.  * PAGER    The pager. "more" is default.
  16.  * PRINTER    Print program. "lpr" is default.
  17.  * DFLTEDITOR    Editor if EDITOR is not in environment.  Default vi.
  18.  * HELPFILE    Location of help info. /usr/local/lib/ded.hlp is default.
  19.  *
  20.  * Define USG for System III/V et al; BSD41 or BSD42 for Berkeley Vmunix.
  21.  *
  22.  *      Note: if you make improvements, we'd like to get them too.
  23.  *          Stuart Cracraft: mclure@sri-unix, ucbvax!menlo70!sri-unix!mclure
  24.  *        Jay Lepreau: lepreau@utah-cs, harpo!utah-cs!lepreau
  25.  *
  26.  * Modifications for USG 4.0 by Jerry Schwarz (eagle!jerry) 6/7/82
  27.  */
  28.  
  29. #ifndef DEDNAME
  30. # define DEDNAME "ded"
  31. #endif
  32.  
  33. #ifndef PAGER
  34. # define PAGER "more"
  35. #endif
  36.  
  37. #ifndef PRINTER
  38. # define PRINTER "lpr"
  39. #endif
  40.  
  41. #ifndef DFLTEDITOR
  42. # define DFLTEDITOR "vi"
  43. #endif
  44.  
  45. #ifndef HELPFILE
  46. # define HELPFILE "/usr/local/lib/ded.hlp"
  47. #endif
  48.  
  49. #include <stdio.h>
  50. #include <signal.h>
  51. #include <ctype.h>
  52. #ifdef USG
  53. # include <sys/termio.h>
  54. # include <sys/types.h>
  55. # include <sys/sysmacros.h>
  56. #else
  57. # include <sgtty.h>
  58. # include <sys/ioctl.h>
  59. #endif USG
  60. #include <sys/param.h>
  61. #include <sys/stat.h>
  62. #ifdef BSD42
  63. # include <sys/dir.h>
  64. #else
  65. # include <dir.h>            /* will be ndir.h on some systems */
  66. # define MAXPATHLEN 512            /* dunno if this is right */
  67. #endif BSD42
  68.  
  69. #include "ded.h"
  70.  
  71. #if !(defined(BSD41) || defined(BSD42) || defined(BSD29))
  72. # define vfork fork
  73. #endif
  74.  
  75. #ifdef BSD41
  76. # define signal sigset
  77. #endif
  78.  
  79. /*
  80.  * CTRL and META must be defined differently under gcc, apparently.
  81.  */
  82. #ifndef CTRL                
  83. # define CTRL(c)    (c & 037)    
  84. #endif /* CTRL */ 
  85. #define META(c)        (c | 0200)
  86.  
  87. /*    Sort Orders - must stay in this order */
  88. #define NOSORT        0        /* directory order */
  89. #define NAME        1        /* filename as string */
  90. #define NUMBER        2        /* filename as number */
  91. #define    SIZE        3
  92. #define    WRITE        4
  93. #define    READ        5
  94. #define NEEDSORT    NAME        /* lowest order requiring sort */
  95. #define NEEDSTAT    SIZE        /* lowest order requiring stat() */
  96. char sortstr[] = "dfnswr";        /* must be in order by above */
  97.  
  98. #define ESC        '\033'
  99. #define CURSOR        43    /* X-coord of cursor, just b4 file */
  100.  
  101. #define DIVCHAR    '-'    /* makes up the divider */
  102. char   divider[132];    /* divides the windows */
  103.  
  104. char    *dedname    = DEDNAME;
  105. char    *pager        = PAGER;
  106. char    *printer    = PRINTER;
  107. char    *dflteditor = DFLTEDITOR;
  108. char    *helpfile   = HELPFILE;
  109.  
  110. #ifdef USG
  111. struct termio    ioctlb;
  112. #else
  113. struct sgttyb    ioctlb;
  114. # ifdef TIOCGLTC
  115. struct ltchars    oltc;
  116. # endif
  117. # ifdef LPASS8
  118. int lpass8 = LPASS8;
  119. # endif
  120. #endif USG
  121.  
  122. int    internflg[10];
  123. #define recursive internflg[0]        /* recursive invocation of ded */
  124. /* 1 is passed down combuf */
  125.  
  126. int    lflg;
  127. int    splitflg;        /* Split screen? */
  128. int    allstatflg;        /* All files stat'ed already?  */
  129. short    dpyflg = FALSE;        /* In display mode? */
  130. int    sortyp = NAME;        /* Key to sort on */
  131. int    rflg = 1;        /* Reverse sort flag */
  132. int    totfiles;        /* Total files */
  133. int    nprint;            /* chars printed in this line so far */
  134. int    blurb;            /* 1=>thing in echo area,0 otherwise  */
  135. int    numdeleted;        /* Number of files marked deleted */
  136. time_t    ttime;            /* Temp time variable */
  137. time_t    year;            /* Six months ago */
  138. char    tempbuf[BUFSIZ];    /* random temporary buffer */
  139.  
  140. int    curfile = 0;        /* Current file */
  141. int    topfile = 0;        /* File at top of screen */
  142. int    curline = 0;        /* Line that we're on */
  143. int    scrlen = 999;    /* Default length of ded index part of screen: */
  144.     /* 999 ==> 2 windows (half size), 0 ==> 1 window (full size) */
  145. int    Worklen = 0;        /* Length of 'working window',the other part*/
  146. int    Worktop = 0;        /* Top of    " " */
  147. int    Tscrlen;        /*Total length of screen,less 1 for cmd line*/
  148. int    scrwid = 79;        /* Width of screen */
  149. char    *thisdir;
  150. #define MAXFLGS 10
  151. char    *flgargv[MAXFLGS+1];
  152. int    freeargv;
  153. struct stat statbuf;
  154.  
  155. char   *CL,
  156.        *UP,            /* Termcap strings we'll use */
  157.        *DO,
  158.        *HO,
  159.        *CM,
  160.        *CD,            /* clear to end of display */
  161.        *CE,
  162.        *AL,            /* insert line */
  163.        *VS,            /* visual start */
  164.        *VE;
  165. char    PC;
  166. short    autowrap;
  167. short    hardtabs;
  168. char   *xsuff = "";        /* default suffixes to exclude */
  169. int    sigint;
  170. char    bufout[BUFSIZ];
  171. struct lbuf *file;
  172.  
  173. #ifdef notyet
  174. long
  175. # ifdef xBSD42
  176.     stbtok();
  177. # else
  178.     sztob();
  179. # endif xBSD42
  180. #endif notyet
  181.  
  182. int    compar();
  183. int    fileselect();
  184. int    catchint();
  185. char   *catargs();
  186. char   *bldnam();
  187. extern char *getname(), *getenv(), *ctime(), *index(), *re_comp(),
  188.     *gets(), *strcpy(), *strcat();
  189. extern char *tgetstr(), *tgoto();
  190.  
  191. #ifdef SIGTSTP
  192. int    onstop();
  193. # define mask(s)    (1 << ((s)-1))
  194. #else
  195. # define stopcatch()
  196. # define stopdefault()
  197. #endif SIGTSTP
  198.  
  199. main(argc, argv)
  200. int    argc;
  201. char   *argv[];
  202. {
  203.     register    int    i,
  204.                     cc;
  205.     int        special,        /* flag says had % or # in cmd */
  206.         otherwin,
  207.         status,
  208.         pid,
  209.         direction,
  210.         j;
  211.     char    nambuf[BUFSIZ];
  212.     char    combuf[BUFSIZ+100];    /* Holds last ! command */
  213.     register int command;    /* Holds last command */
  214.     register char   *t,
  215.                    *tt;
  216.  
  217.  /* Get terminal type */
  218.  
  219.     combuf[0] = '\0';
  220.     setbuf(stdout, (char *) 0);    /* for v7 speed up, vax compatibility -fjl */
  221.     getcap();
  222.  
  223.     freeargv = 2;
  224.  /* Process arg flags. They must be first! */
  225.     for (i=1; i<argc; i++) {
  226.     if (argv[i][0] != '-')
  227.         break;
  228.     if (i > MAXFLGS-2) {
  229.         fprintf(stderr, "Too many flags, %s ignored\n", argv[i]);
  230.         continue;
  231.     }
  232.     cc = argv[i][1];
  233.     if (cc != 'I')            /* may change in future */
  234.         flgargv[freeargv++] = argv[i]; /* leave room for execv params */
  235.     switch (cc) {
  236.       case 'w':            /* Window size */
  237.         if (argv[i][2] == 'h')
  238.         scrlen = 999;        /* Half */
  239.         else if (argv[i][2] == 'f')
  240.         scrlen = 0;        /* Full */
  241.         else
  242.         scrlen = atoi(&argv[i][2]);
  243.         break;
  244.  
  245.       case 's':            /* Initial sort order */
  246.       case 'r':
  247.         if ((t = index(sortstr, argv[i][2])) == 0)
  248.         fprintf(stderr, "Unknown sort order '%c', ignored\n",
  249.           argv[i][2]);
  250.         else {
  251.         sortyp = t - sortstr;
  252.         rflg = (cc == 's') ? 1 : -1;
  253.         }
  254.         break;
  255.         
  256.       case 'x':            /* exclude these file suffixes */
  257.         xsuff = &argv[i][2];
  258.         break;
  259.  
  260.       case 'I':            /* internal flags from higher ded */
  261.         for (t = &argv[i][2]; *t; t++) {
  262.         internflg[*t - '0']++;
  263.         if (*t == '1') {    /* passed down combuf */
  264.             t += 2;        /* skip over 1 and ending quote */
  265.             tt = index(t, '\'');    /* ending quote */
  266.             *tt = '\0';
  267.             strcpy(combuf, t);
  268.             t = tt;
  269.         }
  270.         }
  271.         break;
  272.  
  273.       default:
  274.         fprintf(stderr, "Unknown option %s, ignored.\n", argv[i]);
  275.         break;
  276.     }
  277.     }
  278.     argc -= (i - 1);
  279.     argv += (i - 1);
  280.  
  281.     if (scrlen == 0)            /* full screen */
  282.     scrlen = Tscrlen;
  283.     else if (scrlen == 999)        /* means split in half */
  284.     scrlen = (Tscrlen - 1) >> 1;    
  285.     if (scrlen < 2)
  286.     scrlen = 2;
  287.     if (Tscrlen < scrlen)
  288.     scrlen = Tscrlen;
  289.     splitflg = (Tscrlen > scrlen+1);    /* 1 extra line for separator */
  290.     if (splitflg) {
  291.     Worklen = Tscrlen - (scrlen+1);    /* size of 'working' window */
  292.     Worktop = scrlen + 1;        /* bottom half for now */
  293.     }
  294.     else
  295.     Worklen = 0;
  296.     
  297.     tt = divider + scrwid - 14;
  298.     for (t = divider; t < tt;)    /* arbitrary length */
  299.         *t++ = DIVCHAR;
  300.     *t = '\0';
  301.     (void) time(&ttime);
  302.     year = ttime - 6L * 30L * 24L * 60L * 60L;        /* 6 months ago */
  303.     lflg = 1;
  304.  
  305.     printf("Reading");
  306.     if (argc == 1)
  307.     Readdir(".");
  308.     else if (argc == 2) {    /* for now, we insist on a directory */
  309.     thisdir = argv[1];
  310.         if (stat(thisdir, &statbuf) < 0) {
  311.         printf("\n\007Can't stat %s.\n", argv[1]);
  312.         if (recursive)
  313.         sleep(1);    /* let him see it */
  314.         exit(1);
  315.         }
  316.     if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
  317.         printf("\n\007Sorry, I can't handle this yet.\n");
  318.         if (recursive)
  319.         sleep(1);    /* let him see it */
  320.         exit(1);
  321.     }
  322.     Readdir(thisdir);
  323.     } else {
  324.     /* this alloc's one extra but that's to the good */
  325.     file = ALLOC(struct lbuf, argc);
  326.     if (file == NULL) {
  327.         printf("\n\007Out of memory.\n");
  328.         if (recursive)
  329.         sleep(1);    /* let him see it */
  330.         exit(1);
  331.     }
  332.     while (--argc > 0) {
  333.         if ((totfiles % 10) == 0)
  334.         (void) putchar('.');
  335.         file[totfiles].namep = *++argv;
  336.         file[totfiles++].namlen = strlen(*argv);
  337.     }
  338.     }
  339.     if (totfiles == 0) {
  340.     printf("\n?Empty directory\007\n");
  341.     if (recursive)
  342.         sleep(1);    /* let him see it */
  343.     exit(0);
  344.     }
  345.     if (sortyp >= NEEDSTAT)
  346.     statall();
  347.     if (sortyp > NOSORT)
  348.     qsort((char *)file, totfiles, sizeof (struct lbuf), compar);
  349.  
  350.     /*
  351.      * Put this down here so user can interrupt
  352.      * a mistaken read on a huge directory.
  353.      */
  354.     (void) signal(SIGINT, SIG_IGN);
  355.  
  356.     stopcatch();
  357.     setdpy();
  358.     showscreen(FALSE);
  359.     curxy(CURSOR, 0);
  360.     /*
  361.      * Make quit command different from cmd to quit typing a file,
  362.      * as one hits EOF before one knows and mainline gets the quit.
  363.      *
  364.      * modified 10-3-84 by F. Douglis to accept q after all.
  365.      */
  366.     while ((command = getchar()) != 'Q' && command != 'q') {
  367.     if (blurb)
  368.         clearmsg();
  369. #if defined(TIOCGLTC) && defined(SIGTSTP)
  370.     if (command == oltc.t_suspc)
  371.         command = 'z';
  372. #endif
  373.     switch (command) {
  374. #ifdef SIGTSTP
  375.         case 'z':
  376.         onstop();
  377.         break;
  378. #endif SIGTSTP
  379.  
  380.         case 'x':             /* Abort completely */
  381.         blank();         /* x: To be like Mail, readnews, etc*/
  382.         unsetdpy();
  383.         exit(1);
  384.         break;
  385.         
  386.         case '1':            /* go to top */
  387.         case '\'':            /* apostrophe, for now */
  388.         curline = 0;
  389.         curfile = 0;
  390.             if (topfile != 0) {    /* not on this screen */
  391.             topfile = 0;    /* curses should be doing this!! */
  392.             showscreen(FALSE);
  393.         }
  394.         curxy(CURSOR, 0);
  395.         break;
  396.  
  397.         case '$':            /* go to end */
  398.         case 'G':
  399.         if (topfile + scrlen <= totfiles) { /* not on last screen */
  400.             topfile = totfiles - scrlen + 1;
  401.             showscreen(FALSE);
  402.         }
  403.         curfile = totfiles - 1;
  404.         curline = totfiles - topfile - 1;
  405.         curxy(CURSOR, curline);
  406.         break;
  407.  
  408.         case 'P':         /* Print a file */
  409.         case 'p':        /* do a pr2 */
  410.         if ((i = file[curfile].ltype) == 'd' || i == 'L') {
  411.             telluser("?Can only print files");
  412.             break;
  413.         }
  414.         tempbuf[0] = '\0';
  415.         (void) bldnam(tempbuf, curfile);
  416.         telluser("Printing...");
  417.         while ((pid = vfork()) == -1)
  418.             sleep(3);
  419.         if (pid == 0) {
  420. #ifdef UTAH
  421.             if (command == 'p')        /* little print */
  422.                 execlp("pr2", "pr2", tempbuf, (char *) 0);
  423.             else                /* big print */
  424. #endif
  425.                 execlp(printer, printer, tempbuf, (char *) 0);
  426.             telluser("?Can't find print program '%s'.\n", printer);
  427.             _exit(1);
  428.         }
  429.         while ((i = wait(&status)) != pid && i != -1)
  430.             continue;
  431.         break;
  432.  
  433.         case '.':        /* repeat the previous !/% command */
  434.         if (combuf[0] == '\0') {
  435.             telluser("?No previous command to repeat\007");
  436.             break;
  437.         }
  438.         case '!':         /* Execute a system command in lower window */
  439.                     /* May garbage the screen, but quicker. */
  440.         case '%':        /* Like ! but clear the screen */
  441.         if (command != '.')
  442.             otherwin = splitflg && command == '!';
  443.         promptwin("Command: ", otherwin);
  444.         tempbuf[0] = 'x';    /* dummy kludge */
  445.         if ((command == '.' ? strcpy(tempbuf, combuf) : gets(tempbuf))
  446.           != 0 && tempbuf[0] != '\0') {
  447.             extern   char *skipto();
  448.             register char *op,        /* old ptr */
  449.                   *np;        /* new ptr */
  450.             char     bldbuf[BUFSIZ];
  451.             static   char quote[3] = "\\";
  452.  
  453.             (void) strcpy(combuf, tempbuf); /* remember the command */
  454.             bldbuf[0] = '\0';    
  455.             op = tempbuf;
  456.             special = 0;
  457.             while (cc = *(np = skipto(op, "\\%#@"))) {
  458.             special++;        /* set flag */
  459.             *np++ = '\0';             /* zap and go past it*/
  460.             (void) strcat(bldbuf, op);    /* 1st part */
  461.             switch (cc) {
  462.                 case '%':        /* complete file name */
  463.                 (void) bldnam(bldbuf, curfile);
  464.                 break;
  465.  
  466.                 case '#':        /* # sign, last comp only */
  467.                 (void) strcat(bldbuf, file[curfile].namep);
  468.                 break;
  469.  
  470.                 case '@':        /* "current" directory */
  471.                 if (thisdir)
  472.                     (void) strcat(bldbuf, thisdir);
  473.                 else
  474.                     (void) strcat(bldbuf, ".");
  475.                 break;
  476.  
  477.                 case '\\':
  478.                 special--;
  479.                 quote[1] = *np++;
  480.                 (void) strcat(bldbuf, quote);
  481.             }
  482.             op = np;
  483.             }
  484.             (void) strcat(bldbuf, op);
  485.             /*
  486.              * sh is stupid, so must escape any # comment chars.
  487.              * Really only need to do when preceding char !isspace,
  488.              * but what the hey.
  489.              */
  490.             op = bldbuf;
  491.             while (t = index(op, '#')) {
  492.             if (*(t-1) != '\\') {
  493.                 /* shift the right part over 1 char */
  494.                 for (tt = op + strlen(op) + 1; tt > t; tt--)
  495.                 *tt = *(tt-1);
  496.                 *t = '\\';        /* stick in the \ */
  497.                 op = t + 2;        /* skip over the \# */
  498.             }
  499.             else op = t + 1;
  500.             }
  501.  
  502.             if (!otherwin)
  503.                 blank();
  504.             unsetdpy();
  505.             /*
  506.              * Display expanded or previous command.
  507.              * system() call takes long enuf for him to see it
  508.              * w/o any special delay.
  509.              */
  510.             if (special || command == '.')
  511.             printf( "%s\n", bldbuf);
  512.             (void) signal(SIGINT, SIG_DFL); /* temp kludge here... */
  513.             stopdefault();
  514.             (void) system(bldbuf);
  515.             (void) signal(SIGINT, SIG_IGN);
  516.             printf("CR to return...");
  517.             (void) getchar();
  518.             stopcatch();
  519.             setdpy();
  520.             if (!otherwin)
  521.                 showscreen(FALSE);
  522.             curxy(CURSOR, curline);
  523.         }
  524.         else            /* CR only, or EOF, or error */
  525.             fixup(otherwin || tempbuf[0] == 'x', 1);    /* means EOF*/
  526.         break;
  527.  
  528.         case 'r':         /* Reverse sort */
  529.         curxy(0, Tscrlen);
  530.         printf("reverse ");
  531.         rflg = -1;
  532.         case 's':         /* Normal sort */
  533.         if (command == 's') {
  534.             curxy(0, Tscrlen);
  535.             rflg = 1;
  536.         }
  537.         printf("sort by [s,f,n,r,w]: ");
  538.         command = getchar();
  539.         while ((t = index(sortstr+NEEDSORT, command)) == 0 &&
  540.           (command != CTRL('g'))) {
  541.             curxy(0, Tscrlen);
  542.             ceol();
  543.             if (rflg == -1)
  544.             printf("reverse ");
  545.             printf("sort by size(s), filename(f), filename as number(n), read(r) or write(w) date: ");
  546.             command = getchar();
  547.         }
  548.         if (command == CTRL('g')) {        /* abort */
  549.             (void) putchar(CTRL('g'));        /* echo it */
  550.             clearmsg();
  551.             break;
  552.         }
  553.             sortyp = t - sortstr;
  554.         printf("%c", command);
  555.         if (sortyp >= NEEDSTAT)
  556.             statall();
  557.         qsort((char *)file, totfiles, sizeof (struct lbuf), compar);
  558.         topfile = 0;
  559.         curfile = 0;
  560.         curline = 0;
  561.         showscreen(FALSE);
  562.         curxy(CURSOR, 0);
  563.         break;
  564.  
  565.         case 'e': {         /* Edit a file or directory */
  566.                     /* This section needs cleanup */
  567.         char *execname;
  568.         char **execargv;
  569.         char *edargv[3];
  570.         char *comptr;
  571.  
  572.         tempbuf[0] = '\0';
  573.         (void) bldnam(tempbuf, curfile);
  574.         if ((i = file[curfile].ltype) == 'd' || i == 'L') {
  575.             execname = dedname;
  576.             execargv = flgargv;
  577.             flgargv[0] = dedname;
  578.             if (combuf[0]) {    /* should be after fork */
  579.             comptr = ALLOC(char, 5 + strlen(combuf) + 2);
  580.             strcpy(comptr, "-I01'");    /* 5 */
  581.             strcat(comptr, combuf);        /* strlen(combuf) */
  582.             strcat(comptr, "'");        /* 1 + null */
  583.             flgargv[1] = comptr;
  584.             }
  585.             else {
  586.             flgargv[1] = "-I0";    /* flag 0 means recursive */
  587.             comptr = 0;
  588.             }
  589.             flgargv[freeargv] = tempbuf;
  590.             flgargv[freeargv+1] = 0;
  591.         }
  592.         else {
  593.             if ((t = getenv("EDITOR")) == NULL)
  594.             t = dflteditor;
  595.             execname = t;
  596.             execargv = edargv;
  597.             edargv[0] = t;
  598.             edargv[1] = tempbuf;
  599.             edargv[2] = 0;
  600.         }
  601.         blank();
  602.         unsetdpy();
  603.         stopdefault();        /* both parent and child */
  604.         while ((pid = vfork()) == -1)
  605.             sleep(3);
  606.         if (pid == 0) {
  607.             (void) signal(SIGINT, SIG_DFL);    /* child only */
  608.             execvp(execname, execargv);
  609.             printf("Can't find %s\n", execname);
  610.             _exit(1);
  611.         }
  612.         if (comptr)
  613.             free(comptr);
  614.         while ((i = wait(&status)) != pid && i != -1)
  615.             continue;
  616.         stopcatch();
  617.         setdpy();
  618.         showscreen(FALSE);
  619.         curxy(CURSOR, curline);
  620.         break;
  621.         }
  622.  
  623.         case 'm':         /* 'more' a file */
  624.         if ((i = file[curfile].ltype) == 'd' || i == 'L') {
  625.             telluser("?Can only page thru files");
  626.             break;
  627.         }
  628.         (void) strcpy(tempbuf, pager);
  629.         (void) strcat(tempbuf, " ");
  630.         (void) bldnam(tempbuf, curfile);
  631.         blank();
  632.         unsetdpy();
  633.         (void) signal(SIGINT, SIG_DFL);    /* temp kludge here... */
  634.         stopdefault();
  635.         (void) system(tempbuf);
  636. #ifdef notdef
  637.         if (!sigint)
  638. #endif
  639.             printf("\nCR to return...");
  640.         (void) signal(SIGINT, SIG_IGN);
  641.         stopcatch();
  642.         setdpy();
  643.             (void) getchar();   /* setdpy 1st means non CR will work */
  644.         showscreen(FALSE);
  645.         curxy(CURSOR, curline);
  646.         break;
  647.  
  648.         case 'T':    /* use full screen; basically just cat */
  649.         case 't':    /* type in other window and wrap */
  650.         if ((i = file[curfile].ltype) == 'd' || i == 'L') {
  651.             telluser("?Can only type files");
  652.             break;
  653.         }
  654.         tempbuf[0] = '\0';
  655.         /* little t means wait at EOP (really just mean split) */
  656.         if (type(bldnam(tempbuf, curfile), command == 't'))
  657.             showscreen(FALSE);
  658.         curxy(CURSOR, curline);
  659.         break;
  660.  
  661.         case CTRL('l'):   /* Refresh screen */
  662.         case 'L':        /* Re-stat this page of the display & redisplay */
  663.         showscreen(command == 'L');
  664.         curxy(CURSOR, curline);
  665.         break;
  666.         
  667.         case 'l':        /* Re-stat this file & redisplay */
  668.         tempbuf[0] = '\0';
  669.         if (gstat(bldnam(tempbuf, curfile), curfile) < 0)
  670.             telluser("?Can't stat %s", tempbuf);
  671.         curxy(0, curline);
  672.         pentry(curfile);
  673.         curxy(CURSOR, curline);
  674.         break;
  675.  
  676.         case CTRL('v'):        /* emacs lovers */
  677.         case CTRL('f'):        /* for vi lovers */
  678.         case 'f':            /* forward window */
  679.         fscreen();
  680.         break;
  681.  
  682.         /* meta-v works if you have LPASS8 in your kernel and a metakey */
  683.         case META('v'):        /* for emacs lovers */
  684.         case CTRL('b'):        /* for vi lovers */
  685.         case 'b':            /* backward window */
  686.         bscreen();
  687.         break;
  688.         
  689.         case 'j':            /* for vi lovers */
  690.         case CTRL('n'):        /* for emacs lovers */
  691.         case '\r':            /* for regular folks */
  692.         case '\n':             /* next file */
  693.         if (curfile == totfiles - 1)
  694.             telluser("?At end of files");
  695.         else
  696.             if (curline == scrlen - 1) {
  697.             topfile = curfile;
  698.             curline = 0;
  699.             showscreen(FALSE);
  700.             curxy(CURSOR, 0);
  701.             downline();
  702.             }
  703.             else
  704.             downline();
  705.         break;
  706.         
  707.         case '\b':            /* nice on my terminal */
  708.         case CTRL('p'):        /* for emacs lovers */
  709.         case 'k':            /* for vi and rogue lovers */
  710.         case '-':            /* more vi */
  711.         if (curfile == 0)
  712.             telluser("?At start of files");
  713.         else
  714.             if (curline == 0) {
  715.             topfile = curfile - scrlen + 1;
  716.             curline = scrlen - 1;
  717.             showscreen(FALSE);
  718.             curxy(CURSOR, curline);
  719.             upline();
  720.             }
  721.             else
  722.             upline();
  723.         break;
  724.  
  725.         case 'h':        /* Help */
  726.         if (type(helpfile, TRUE))        /* wait */
  727.             showscreen(FALSE);
  728.         curxy(CURSOR, curline);
  729.         break;
  730.  
  731.         case 'd':         /* delete file */
  732.         if (file[curfile].flg&DELETED)
  733.             telluser("?Already marked deleted");
  734.         else {
  735.             numdeleted++;
  736.             file[curfile].flg |= DELETED;
  737.             printf("D%c", '\b');    /* XXX */
  738.             if (curfile == totfiles - 1) /* last file, no motion */
  739.             break;
  740.             if (curline + 1 == scrlen)
  741.             fscreen();
  742.             downline();
  743.         }
  744.         break;
  745.  
  746.         case 'u':         /* undelete file */
  747.         if (!file[curfile].flg&DELETED)
  748.             telluser("?Not marked deleted");
  749.         else {
  750.             numdeleted--;
  751.             file[curfile].flg &= ~DELETED;
  752.             printf(" %c", '\b');    /* XXX */
  753.         }
  754.         break;
  755.         
  756.         case '/':            /* search for a filename */
  757.         direction = 1;
  758.         case '?':            /* backwards search */
  759.         if (command == '?')
  760.             direction = -1;
  761.         promptwin("Regular Expr: ", otherwin = splitflg);
  762.         (void) gets(tempbuf);
  763.         if (t = re_comp(tempbuf)) {
  764.             fixup(otherwin, 1);
  765.             telluser("%s", t);        /* error */
  766.             break;
  767.           }
  768.         /* start at next file if we`re using the last regexp */
  769.         for (i = curfile + direction * (tempbuf[0] == '\0');
  770.              direction == 1 ? i < totfiles : i >= 0;
  771.              i += direction) {
  772.             register struct lbuf *p = &file[i];
  773.  
  774.             switch (re_exec(p->namep)) {
  775.                 case -1:
  776.                 fixup(otherwin, 1);
  777.                 telluser("Internal error in re_exec");
  778.                 goto mainloop;
  779.                 
  780.             case 1:                /* found it */
  781.                 curfile = i;
  782.                 /* moved to new screen? */
  783.                 if ( direction == 1 ?
  784.                   (curfile - topfile > scrlen-1) :    /* forward */
  785.                   (curfile < topfile) ) {    /* backward */
  786.                     setdpy();
  787.                 displayfile(curfile);
  788.                 }
  789.                 else {            /* same screen */
  790.                 curline = curfile - topfile;
  791.                 fixup(otherwin, 1);
  792.                 }
  793.                 goto mainloop;
  794.             }
  795.         }
  796.         fixup(otherwin, 1);
  797.         telluser("No match");
  798.         break;
  799.             
  800.         default: 
  801.         /*
  802.             if (command == 'q')
  803.             telluser("Quit command is now 'Q' ('x' to abort w/o deleting)");
  804.         else
  805.         */
  806.             telluser("Unknown command %c. Type h for help", command);
  807.         break;
  808.     }
  809. mainloop:;
  810.     /* This is so ^D works repeatedly to escape ! and / commands */
  811.     if (feof(stdin))
  812.         clearerr(stdin);
  813.     }
  814.  
  815.     /* 'Q' typed */
  816.     if (numdeleted) {
  817.     blank();
  818.     setbuf(stdout, bufout);    /* buffered output here, faster */
  819.     printf("The following %s marked for deletion:\n",
  820.         (numdeleted == 1) ? "is" : "are");
  821.     typefiles();
  822.     printf("\nShall I delete %s? ",
  823.         (numdeleted == 1) ? "this" : "these");
  824.     (void) fflush(stdout);
  825.     setbuf(stdout, (char *) 0);
  826.     if ((command = getchar()) != 'y') {
  827.         showscreen(FALSE);
  828.         curxy(CURSOR, curline);
  829.         goto mainloop;
  830.     }
  831.     else {
  832.         printf("y\n");
  833.         /*
  834.          * unlink`ing a lot of files takes a while, so do it
  835.          * asyncronously.  We really need to estimate how big
  836.          * any subdirs are, too.
  837.          * If recursive the user normally can ^Z and 'bg' it.
  838.          */
  839.         if (
  840. #ifdef SIGTSTP
  841.         recursive &&
  842. #endif
  843.             numdeleted > 20 && fork() > 0)
  844.         exit(0);        /* parent */
  845.         stopdefault();        /* so can be put into background */
  846.         unsetdpy();
  847.         for (i = 0; i < totfiles; i++)
  848.         if (file[i].flg&DELETED) {
  849.             nambuf[0] = '\0';
  850.             (void) bldnam(nambuf, i);
  851.             if (file[i].ltype == 'd')
  852.             rm(nambuf);
  853.             else if (unlink(nambuf) < 0)
  854.             printf("Delete of %s failed.\n", nambuf);
  855.         }
  856.         exit(0);
  857.     }
  858.     }
  859.     else {
  860.     blank();
  861.     unsetdpy();
  862.     exit(0);
  863.     }
  864.     /*NOTREACHED*/
  865. }                    /* end of main() */
  866.  
  867. /*
  868.  * Display files marked for deletion.
  869.  */
  870. typefiles()
  871. {
  872.     register int i, j;     
  873.     int longsiz, maxperln, numout, fillen;
  874.  
  875.     /* First find longest filename */
  876.     longsiz = numout = 0;
  877.     for (i = 0; i < totfiles; i++)
  878.     if (file[i].flg&DELETED && file[i].namlen > longsiz)
  879.         longsiz = file[i].namlen;
  880.     maxperln = max(1, scrwid / (longsiz + 4));    /* 3 blanks plus type char */
  881.  
  882.     for (i = 0; i < totfiles; i++)
  883.     if (file[i].flg&DELETED) {
  884.         /* print type char, do not expand symlinks */
  885.         pname(&file[i], scrwid, TRUE, FALSE);
  886.         numout++;
  887.         if ((numout % maxperln) == 0)
  888.         (void) putchar('\n');
  889.         else {            /* append filler */
  890.         fillen = longsiz + 3 - file[i].namlen;
  891.         for (j = 0; j < fillen; j++)
  892.             (void) putchar(' ');
  893.         }
  894.     }
  895. }
  896.  
  897. fscreen()
  898. {
  899.     if (topfile + scrlen - 1 > totfiles - 1)
  900.     telluser("?No remaining windows");
  901.     else {
  902.     topfile = topfile + scrlen - 1;
  903.     curfile = topfile;
  904.     curline = 0;
  905.     showscreen(FALSE);
  906.     curxy(CURSOR, 0);
  907.     }
  908. }
  909.  
  910. bscreen()
  911. {
  912.     if (topfile == 0 && curfile == 0)
  913.     telluser("?No previous windows");
  914.     else {
  915.     topfile = max(topfile - scrlen + 1, 0);
  916.     curfile = topfile;
  917.     curline = 0;
  918.     showscreen(FALSE);
  919.     curxy(CURSOR, 0);
  920.     }
  921. }
  922.  
  923. /*
  924.  * Blank and redisplay the index.
  925.  * If restat is set, then stat the files again.
  926.  */
  927. showscreen(restat)
  928. int restat;
  929. {
  930.     int        i,
  931.         numprint;
  932.  
  933.     blank();
  934.     home();
  935.     setbuf(stdout, bufout);    /* buffered output here, faster! --fjl */
  936.     numprint = 0;
  937.     for (i = topfile; (numprint < scrlen) && (i < totfiles); i++) {
  938.     if (restat) {
  939.         tempbuf[0] = '\0';
  940.         (void) gstat(bldnam(tempbuf, i), i);
  941.     }
  942.     pentry(i);
  943.     numprint++;
  944.     (void) putchar('\n');
  945.     }
  946.     if (splitflg)
  947.         printf("%s\n", divider);
  948.     (void) fflush(stdout);        /* reset for display functions */
  949.     setbuf(stdout, (char *) 0);
  950. }
  951.  
  952.     /* Reads directory dir */
  953. Readdir(dir)
  954. char   *dir;
  955. {
  956.     /* Want to cast the last arg to (int ())0 but can`t in C */
  957.     if ((totfiles = Scandir(dir, &file, fileselect, NULL)) < 0) {
  958.     if (totfiles == -1)
  959.         printf("\n\007Sorry, %s unreadable.\n", dir);
  960.     else                /* -2 */
  961.         printf("\n\007Out of memory.\n");
  962.     if (recursive)
  963.         sleep(1);    /* let him see it */
  964.     exit(1);            /* or could be out of room */
  965.     }
  966. }
  967.  
  968.     /* Stats the given file */
  969. int
  970. gstat(filename, nfile)
  971. char *filename;
  972. int nfile;
  973. {
  974.     register struct lbuf *p = &file[nfile];
  975.  
  976.     p->flg |= STATDONE;
  977.     p->lmode = 0;
  978.     p->lino = 0;
  979.     p->ltype = '-';
  980.  
  981.     if (lstat(filename, &statbuf) < 0)
  982.     return -1;
  983.     p->lino = statbuf.st_ino;
  984.     p->lsize = statbuf.st_size;
  985.     switch (statbuf.st_mode & S_IFMT) {
  986.     case S_IFDIR: 
  987.         p->ltype = 'd';
  988.         break;
  989. #ifdef S_IFLNK
  990.     case S_IFLNK: {
  991.         struct stat stbuf;
  992.  
  993.         if (stat(filename, &stbuf) == 0 &&
  994.           (stbuf.st_mode & S_IFMT) == S_IFDIR)
  995.         p->ltype = 'L';
  996.         else
  997.         p->ltype = 'l';
  998.         break;
  999.     }
  1000. #endif
  1001. #ifdef S_IFSOCK
  1002.     case S_IFSOCK:
  1003.         p->ltype = 's';
  1004.         break;
  1005. #endif        
  1006.     case S_IFBLK: 
  1007.         p->ltype = 'b';
  1008.         p->lsize = statbuf.st_rdev;
  1009.         break;
  1010.     case S_IFCHR: 
  1011.         p->ltype = 'c';
  1012.         p->lsize = statbuf.st_rdev;
  1013.         break;
  1014.     }
  1015.     p->lmode = statbuf.st_mode & ~S_IFMT;
  1016.     p->luid = statbuf.st_uid;
  1017.     p->lgid = statbuf.st_gid;
  1018.     p->lnl = statbuf.st_nlink;
  1019.     p->latime = statbuf.st_atime;
  1020.     p->lmtime = statbuf.st_mtime;
  1021.     return 0;
  1022. }
  1023.  
  1024. pentry(whichone)
  1025. int    whichone;
  1026. {
  1027.     register struct lbuf *p = &file[whichone];
  1028.     register char  *cp;
  1029.     time_t tim;
  1030.     char buf[MAXPATHLEN];
  1031.  
  1032.     if (! (p->flg&STATDONE)) {
  1033.     *buf = '\0';
  1034.     (void) gstat(bldnam(buf, whichone), whichone);
  1035.     }
  1036.     nprint = 0;            /* keep track of how many chars printed */
  1037. #ifdef notyet
  1038.     if (iflg)
  1039.     printf("%5u ", p->lino);
  1040.     if (sflg)
  1041.     printf("%4ld ",
  1042. #ifdef xBSD42                /* not yet */
  1043.         stbtok(p->lblks));
  1044. #else
  1045.         sztob(p->lsize));
  1046. #endif
  1047. #endif notyet
  1048.     if (lflg) {
  1049.     (void) putchar(p->ltype); nprint++;
  1050.     pmode(p->lmode);            /* 10 chars */
  1051.     printf("%2d ", p->lnl); nprint += 3;    /* XXX */
  1052.     if (cp = getname(p->luid))
  1053.         printf("%-9.9s", cp);
  1054.     else
  1055.         printf("%-9u", p->luid);
  1056.     nprint += 9;
  1057.     if (p->ltype == 'b' || p->ltype == 'c')
  1058.         printf("%3d,%3d", major((int) p->lsize), minor((int) p->lsize));
  1059.     else
  1060.         printf("%7ld", p->lsize);
  1061.     nprint += 7;
  1062.     if (sortyp == READ)
  1063.         tim = p->latime;
  1064.     else
  1065.         tim = p->lmtime;
  1066.     cp = ctime(&tim);
  1067.     if (tim < year)
  1068.         printf(" %-7.7s %-4.4s ", cp + 4, cp + 20);
  1069.     else
  1070.         printf(" %-12.12s ", cp + 4);
  1071.     nprint += 14;
  1072.     }
  1073.     printf("%c ", p->lino == 0 ? '-' : (p->flg&DELETED ? 'D' : ' '));
  1074.     nprint += 2;
  1075.     /* 45 chars so far */
  1076.     /* TRUE, TRUE ==> prt the "type", expand symlinks */
  1077.     pname(p, scrwid - nprint, TRUE, TRUE);
  1078. }
  1079.  
  1080. int
  1081. compar(p1, p2)
  1082. register struct lbuf *p1, *p2;
  1083. {
  1084.     register char *p;
  1085.     register long n1, n2;
  1086.     static char digits[] = "0123456789";
  1087.     extern long atol();
  1088.     extern char *skipover();
  1089.  
  1090.     switch (sortyp) {
  1091.     case NAME:
  1092.         return rflg * strcmp(p1->namep, p2->namep);
  1093.     case NUMBER:
  1094.         if (*skipover(p1->namep, digits) != '\0' ||
  1095.         *skipover(p2->namep, digits) != '\0')
  1096.         return rflg * strcmp(p1->namep, p2->namep);
  1097.         n1 = atol(p1->namep);
  1098.         n2 = atol(p2->namep);
  1099.         return rflg * (n1 - n2);
  1100.     case SIZE:
  1101.         return rflg * (p2->lsize - p1->lsize);
  1102.     case WRITE:
  1103.         return rflg * (p2->lmtime - p1->lmtime);
  1104.     case READ:
  1105.         return rflg * (p2->latime - p1->latime);
  1106.     default:
  1107.         telluser("?Syserr - impossible sort order %d\007", sortyp);
  1108.         return 0;
  1109.     }
  1110.     /*NOTREACHED*/
  1111. }
  1112.  
  1113. ceod()
  1114. {
  1115.     putpad(CD);
  1116. }
  1117.  
  1118. ceol()
  1119. {
  1120.     putpad(CE);
  1121. }
  1122.  
  1123. blank()
  1124. {
  1125.     putpad(CL);
  1126. }
  1127.  
  1128. home()
  1129. {
  1130.     if (HO == 0)
  1131.     curxy(0, 0);
  1132.     else
  1133.     putpad(HO);
  1134. }
  1135.  
  1136. insline()
  1137. {
  1138.     putpad(AL);
  1139. }
  1140.  
  1141. /*
  1142.    Yes, folks, we use direct cursor addressing to get to next line!
  1143.    Before you mumble "What sort of cretin would do this?" here's
  1144.    the reason. We don't use \n since that obviously won't work.
  1145.    We don't use \012 since virgin version 7 makes that into a crlf.
  1146.    We don't use raw mode since we type out help files efficently,
  1147.    and we don't want to switch modes all the time. So enjoy. -- SMC
  1148.  */
  1149. downline()
  1150. {
  1151.     curxy(CURSOR, ++curline);
  1152.     curfile++;
  1153. }
  1154.  
  1155. upline()
  1156. {
  1157.     putpad(UP);
  1158.     curline--;
  1159.     curfile--;
  1160. }
  1161.  
  1162. /*VARARGS1*/
  1163. telluser(msg, args)
  1164. char   *msg;
  1165. {
  1166.     curxy(0, Tscrlen);
  1167.     ceol();
  1168.     printf(msg, args);
  1169.     curxy(CURSOR, curline);
  1170.     blurb++;
  1171. }
  1172.  
  1173. clearmsg()
  1174. {
  1175.     curxy(0, Tscrlen);
  1176.     ceol();
  1177.     curxy(CURSOR, curline);
  1178.     blurb = 0;
  1179. }
  1180.  
  1181. curxy(col, lin)
  1182. {
  1183.     char   *cmstr = tgoto(CM, col, lin);
  1184.     putpad(cmstr);
  1185. }
  1186.  
  1187. short column;
  1188. extern char *fgets();
  1189.  
  1190. /*
  1191.  * Modified to type help file & others. fjl 5/81
  1192.  * This function is rather a mess right now.
  1193.  */
  1194. type(filestr, waitflg)
  1195. char *filestr;
  1196. {
  1197.     int        helpfd = 5;
  1198.     FILE    *fd = stdin;
  1199.     register int     i;
  1200.     register int     cc = 0;
  1201.     int        cur_scrl;        /* current screen length */
  1202.     char    helpbuf[BUFSIZ];
  1203.     
  1204.     if (splitflg && waitflg)
  1205.         fd = fopen(filestr, "r");
  1206.     else
  1207.         helpfd = open(filestr, 0);
  1208.     if (helpfd < 0 || fd == NULL) {
  1209.         telluser("?Unable to open %s", filestr);
  1210.     return FALSE;
  1211.     }
  1212.     
  1213.     (void) signal(SIGINT, catchint);
  1214.     sigint = 0;
  1215.     
  1216.     if (splitflg && waitflg) {
  1217.     setbuf(stdout, bufout);        /* to speed it up */
  1218.     cur_scrl = totfiles - topfile;    /* topfile starts at 0 */
  1219.     Worktop = ((cur_scrl < scrlen) ? cur_scrl : scrlen) + 1;
  1220.     do {
  1221.         curxy(0, Worktop);
  1222.         ceod();
  1223.         for (i = Worktop; (i < Tscrlen) && !sigint && (cc != EOF); i++) {
  1224.         column = 0;
  1225.         while ((cc = getc(fd)) != EOF) {
  1226.             if (typec(cc, fd))
  1227.                 break;
  1228.             }
  1229.         }
  1230.         (void) fflush(stdout);
  1231.     } while (!sigint && (cc != EOF) && waitchk(waitflg));
  1232.     
  1233.     if (feof(fd))    
  1234.         printf("===== End-of-File =====\n");
  1235.     (void) fflush(stdout);
  1236.     setbuf(stdout, (char *) 0);
  1237.     (void) fclose(fd);
  1238.     return FALSE;        /* means needs no re-display */
  1239.     }
  1240.     else {            /* full screen typeout */
  1241.         blank();
  1242.     unsetdpy();        /* so page mode works if we've got it */
  1243.     stopdefault();            /* ??? */
  1244.         while ((i = read (helpfd, helpbuf, sizeof helpbuf)) > 0 && !sigint)
  1245.         (void) write(1, helpbuf, i);
  1246.     (void) close(helpfd);
  1247.     stopcatch();
  1248.     setdpy();
  1249.         if (!sigint) {
  1250.         curxy(0, Tscrlen);
  1251.         printf("CR to return...");
  1252.             (void) getchar();
  1253.         }
  1254.     return TRUE;
  1255.     }
  1256. }
  1257.  
  1258. /* Used by "type" to put out a char in other window, doing line-folding,
  1259.  * tab expansion, ^L interpreting, etc.  Returns non-0 iff put out a \n
  1260.  * during it.
  1261.  */
  1262. typec(cc, fd)
  1263. register int cc;
  1264. FILE *fd;
  1265. {
  1266.     register int i;
  1267.     register int newline = 0;
  1268. chklen:
  1269.     if (cc == '\t') {
  1270.         if (!hardtabs) {
  1271.         for (i = 7; i; i--)
  1272.             newline += typec(' ', fd);
  1273.         cc = ' ';
  1274.         }
  1275.         else            /* 8 should not be hardwired here */
  1276.         column = (column + 8) & ~07;  /* round down to multiple of 8 */
  1277.     }
  1278.     /* If am then can''t use whole line cause it will scroll */
  1279.     if (++column > (scrwid + (!autowrap))) {
  1280.         if (cc != '\t' && cc != '\n')
  1281.         (void) ungetc(cc, fd);
  1282.         cc = '\n';
  1283.     }
  1284.     if (cc == CTRL('l')) {
  1285.         (void) putchar('^');
  1286.         cc = 'L';
  1287.         goto chklen;
  1288.     }
  1289.     if (putchar(cc) == '\n')
  1290.         newline++;
  1291.     return newline;
  1292. }
  1293.         
  1294. waitchk(waitflg)
  1295. {
  1296.     register int c;
  1297.  
  1298.     if (!waitflg)
  1299.         return 1;
  1300.     (void) fflush(stdout);
  1301.     setbuf(stdout, (char *) 0);
  1302. prompt:
  1303.     curxy(0, Tscrlen);
  1304.     printf ("---Continue---");
  1305.     ceol();
  1306.     curxy(0, Tscrlen);
  1307.     /* need to handle syscall restarting */
  1308.     if ((c = getchar()) == 'q')
  1309.         sigint = 1;        /* simulate interrupt */
  1310. #ifdef SIGTSTP
  1311.     else if (c == oltc.t_suspc) {
  1312.         onstop();
  1313.         goto prompt;
  1314.     }
  1315. #endif
  1316.     ceol();
  1317.     setbuf(stdout, bufout);
  1318.     if (sigint)
  1319.         return 0;        /* avoids clear of screen */
  1320.     return 1;
  1321. }
  1322.  
  1323. setdpy()
  1324. {
  1325.     static int dpyinit;
  1326. #ifdef USG
  1327.     static struct termio newb;
  1328. #else    
  1329.     static struct sgttyb newb;
  1330. #endif USG
  1331. #ifdef TIOCGLTC        /* this better be defined if SIGTSTP is */
  1332.     static struct ltchars nltc;
  1333.  
  1334.     if (!dpyinit) {
  1335.     (void) ioctl(0, TIOCGLTC, (char *) &oltc);
  1336.     nltc = oltc;
  1337.     nltc.t_suspc = '\377';        /* ^Z */
  1338.     nltc.t_dsuspc = '\377';        /* ^Y */
  1339.     nltc.t_lnextc = '\377';        /* ^V */
  1340.     }
  1341.     (void) ioctl(0, TIOCSLTC, (char *) &nltc);
  1342. #endif TIOCGLTC
  1343.  
  1344. #ifdef USG
  1345.     if (!dpyinit) {
  1346.     dpyinit++;
  1347.     (void) ioctl(0, TCGETA, (char *) &ioctlb);
  1348.     newb = ioctlb;
  1349.     newb.c_lflag &= ~ICANON;
  1350.     newb.c_lflag &= ~ECHO;
  1351.     newb.c_cc[VMIN] = 1;
  1352.     newb.c_cc[VTIME] = 1;
  1353.     }
  1354.     (void) ioctl(0, TCSETA, (char *) &newb);
  1355.  
  1356. #else
  1357.     if (!dpyinit) {
  1358.     dpyinit++;
  1359.     (void) ioctl(0, TIOCGETP, (char *) &ioctlb);
  1360.     newb = ioctlb;
  1361.     newb.sg_flags |= CBREAK;
  1362.     newb.sg_flags &= ~(ECHO|XTABS);
  1363.     }
  1364.     (void) ioctl(0, TIOCSETP, (char *) &newb);
  1365. # ifdef LPASS8
  1366.     (void) ioctl(0, TIOCLBIS, (char *) &lpass8);
  1367. # endif
  1368. #endif USG
  1369.  
  1370.     dpyflg = TRUE;
  1371.     putpad(VS);
  1372. }
  1373.  
  1374. unsetdpy()
  1375. {
  1376. #ifdef USG
  1377.     (void) ioctl(0, TCSETA, (char *) &ioctlb);
  1378. #else
  1379.     (void) ioctl(0, TIOCSETP, (char *) &ioctlb);
  1380. #endif USG
  1381. #ifdef TIOCGLTC
  1382.     (void) ioctl(0, TIOCSLTC, (char *) &oltc);
  1383. #endif
  1384. # ifdef LPASS8
  1385.     (void) ioctl(0, TIOCLBIC, (char *) &lpass8);
  1386. # endif
  1387.     dpyflg = FALSE;
  1388.     putpad(VE);
  1389. }
  1390.  
  1391. getcap()
  1392. {
  1393.     static char tcapbuf[256];
  1394.     char tbuf[1024];
  1395.     char   *ap;
  1396.     char   *term;
  1397.     char   *xPC;
  1398.  
  1399.     term = getenv("TERM");
  1400.     if (term == 0) {
  1401.     fprintf(stderr, "No TERM in environment\n");
  1402.     exit(1);
  1403.     }
  1404.  
  1405.     switch (tgetent(tbuf, term)) {
  1406.     case -1: 
  1407.         fprintf(stderr, "Cannot open termcap file\n");
  1408.         exit(2);
  1409.     case 0: 
  1410.         fprintf(stderr, "%s: unknown terminal", term);
  1411.         exit(3);
  1412.     }
  1413.  
  1414.     ap = tcapbuf;
  1415.  
  1416.     Tscrlen = tgetnum("li") - 1;
  1417.     scrwid = tgetnum("co") - 1;        /* lose 1 so won`t scroll in last line */
  1418.  
  1419.     UP = tgetstr("up", &ap);
  1420.     DO = tgetstr("do", &ap);
  1421.     CD = tgetstr("cd", &ap);
  1422.     CE = tgetstr("ce", &ap);
  1423.     HO = tgetstr("ho", &ap);        /* home, optional */
  1424.     CL = tgetstr("cl", &ap);
  1425.     CM = tgetstr("cm", &ap);
  1426.     AL = tgetstr("al", &ap);        /* insert line, optional */
  1427.     VS = tgetstr("vs", &ap);        /* visual start */
  1428.     VE = tgetstr("ve", &ap);
  1429.     autowrap = tgetflag("am");        /* use for smarts in "type" */
  1430.     hardtabs = tgetflag("pt");        /* same */
  1431.  
  1432.     xPC = tgetstr("pc", &ap);
  1433.     if (xPC)
  1434.     PC = *xPC;
  1435.  
  1436.     if ((CM == 0) || (CL == 0) || (UP == 0)) {
  1437.     fprintf(stderr, "Tty must have cursor addr, clear, and 4 cursor motions.\n");
  1438.     exit(1);
  1439.     }
  1440.     if (Tscrlen <= 0 || scrwid <= 0) {
  1441.     fprintf(stderr, "Must know the screen size\n");
  1442.     exit(1);
  1443.     }
  1444. }
  1445.  
  1446. catchint()
  1447. {
  1448.     (void) signal(SIGINT, SIG_IGN);    /* reset it */
  1449.     sigint = 1;
  1450. }
  1451.  
  1452. /*VARARGS2*/
  1453. char *
  1454. bldnam(str, filidx, lp)
  1455. register char *str;
  1456. int filidx;
  1457. struct lbuf *lp;
  1458. {
  1459.     if (thisdir) {
  1460.         (void) strcat(str, thisdir);
  1461.         (void) strcat(str, "/");
  1462.     }
  1463.     if (filidx < 0)            /* XXX */
  1464.         (void) strcat(str, lp->namep);
  1465.     else
  1466.         (void) strcat(str, file[filidx].namep);
  1467.     return str;
  1468. }
  1469.  
  1470. promptwin(str, otherwin)
  1471. char *str;
  1472. {
  1473.     if (otherwin) {        /* do in lower window */
  1474.     int cur_scrl = totfiles - topfile;
  1475.     Worktop = ((cur_scrl < scrlen) ? cur_scrl : scrlen) +1;
  1476.     curxy(0, Worktop);
  1477.     ceod();
  1478.     }
  1479.     else {
  1480.     curxy(0, Tscrlen);
  1481.     ceol();
  1482.     blurb++;
  1483.     }
  1484.     unsetdpy();
  1485.     printf(str);
  1486. }
  1487.         
  1488. /* 
  1489.  * fix up display after numout lines wrtten in cooked mode.
  1490.  *
  1491.  * Since we were in cooked mode, the CR ending the gets is echoed and
  1492.  * we lost the first line of the display.  So we re-insert it.
  1493.  */
  1494. fixup(otherwin, numout)
  1495. {
  1496.     setdpy();
  1497.     if (!otherwin) {
  1498.     if (AL == 0 || numout > 1)    /* no insert line capability */
  1499.         showscreen(FALSE);
  1500.     else {                /* be a little sneakier */
  1501.         curxy(0, Tscrlen-1);    /* go back to where prompt */
  1502.         ceol();              /*  is now, and blank it */
  1503.         home();
  1504.         insline();            /* make some room */
  1505.         pentry(topfile);
  1506.         (void) putchar('\n');
  1507.     }
  1508.     }
  1509.     curxy(CURSOR, curline);
  1510. }        
  1511.  
  1512. #ifdef SIGTSTP
  1513. onstop()
  1514. {
  1515.     curxy(0, Tscrlen - 2);    /* so top line stays at top when stopped */
  1516.     ceod();
  1517.     unsetdpy();
  1518.     stopdefault();
  1519.     (void) kill(0, SIGTSTP);        /* hold it right there! */
  1520.     stopcatch();
  1521.     setdpy();
  1522.     showscreen(FALSE);        /* false ==> don`t restat.  Arguable. */
  1523.     curxy(CURSOR, curline);
  1524. }
  1525.  
  1526. stopdefault()
  1527. {
  1528.     (void) signal(SIGTSTP, SIG_DFL);
  1529. #ifdef BSD42
  1530.     (void) sigsetmask(sigblock(0) &~ mask(SIGTSTP));
  1531. #endif
  1532. }
  1533.  
  1534. stopcatch()
  1535. {
  1536.     (void) signal(SIGTSTP, onstop);
  1537. }
  1538. #endif SIGTSTP
  1539.  
  1540. static int
  1541. fileselect(dp)
  1542.     struct direct *dp;
  1543. {
  1544.     register char *p = dp->d_name;
  1545.     register int len;
  1546.     register char *q, *sq;
  1547.     char buf[56];
  1548.  
  1549.     if (*p == '.') {
  1550.         switch (*(p+1)) {
  1551.       case '\0':            /* "." */
  1552.         return 0;
  1553.       case '.':
  1554.         if (*(p+2) == '\0')        /* ".." */
  1555.             return 0;
  1556.     }
  1557.     }
  1558.     len = dp->d_namlen;
  1559.     /* This is written so that a null suffixes string will always return 1 */
  1560.     p = p + len;            /* p now points at ending null */
  1561.     (void) strcpy(buf, xsuff);
  1562.     sq = buf;
  1563.     (void) strcat(sq, "|");
  1564.     for (q = sq; *q; q++)
  1565.     if (*q == '|') {
  1566.         if ((len = q - sq) && !strncmp(p - len, sq, len))
  1567.         return 0;
  1568.         sq = q + 1;            /* skip over the | */
  1569.     }
  1570.     return 1;
  1571. }
  1572.  
  1573. /* stat's all the files if it hasn't been done yet */
  1574. statall()
  1575. {
  1576.     register int i;
  1577.     register struct lbuf *lp;
  1578.     struct lbuf *endbuf = file + totfiles;    /* one past end */
  1579.     char buf[MAXPATHLEN];
  1580.  
  1581.     if (allstatflg)
  1582.     return;
  1583.     for (lp = file; lp < endbuf; lp++) {
  1584.     if (!lp->flg&STATDONE) {
  1585.         i = lp - file;
  1586.         *buf = '\0';
  1587.         (void) gstat(bldnam(buf, i), i);
  1588.     }
  1589.     }
  1590.     allstatflg++;
  1591. }
  1592.  
  1593. /* The following routines are more or less from Charles Hill, philabs!crh */
  1594.  
  1595. /* move to the indicated file number */
  1596. displayfile(fnum)
  1597. int fnum;
  1598. {
  1599.  
  1600.   /* redraw if file not already on screen */
  1601.   if ( (fnum < topfile) || (fnum >= topfile + scrlen) ) {
  1602.      topfile = fnum/(scrlen - 1) * (scrlen - 1);
  1603.      /* get rid of 1 file final windows unless necessary */
  1604.      if ( (topfile == totfiles - 1) && (topfile - scrlen + 1 >= 0) )
  1605.        topfile = topfile - scrlen + 1;
  1606.      showscreen(FALSE);
  1607.   }
  1608.   curfile = fnum;
  1609.   curline = fnum - topfile;
  1610.   curxy(CURSOR, curline);
  1611. }
  1612.